<template>
  <div class="gantt-timeline">
    <div class="gantt-timeline-padding_block" :style="{ width: paddingWidth + 'px' }"></div>
    <template v-for="(block, index) in allBlocks" :key="index">
      <div class="gantt-timeline-block" :style="{ width: blockWidth + 'px' }">
        <slot :block="block" :getTimeScales="getTimeScales">
          <div class="gantt-timeline-label" :style="heightStyle">
            {{ formatBlock(block) }}
          </div>
          <div v-if="showTimeScale" class="gantt-timeline-scale" :style="heightStyle">
            <div
                v-for="(time, index) in getTimeScales(block)"
                :key="index"
                :style="cellWidthStyle"
            >
              {{ formatTime(time) }}
            </div>
          </div>
        </slot>
      </div>
    </template>
  </div>
</template>

<script lang="ts" setup>
import { computed, PropType } from 'vue';
import dayjs from 'dayjs';
import {
  add,
  addDays,
  addYears,
  addMonths,
  startOfMonth,
  endOfMonth,
  startOfDay,
  startOfYear,
  endOfYear,
  endOfDay,
  isBefore,
  isAfter,
  isEqual,
  isSameDay,
  isSameMonth,
  isSameYear,
  format,
  parseISO,
  intervalToDateArray,
  isWithinInterval,
  subDays,
  addMinutes
} from 'date-fns';

import { MINUTE_OF_ONE_HOUR, MINUTE_OF_ONE_DAY } from '@/utils/timeLineUtils.ts';

const props = defineProps({
  start: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  end: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  cellWidth: {
    type: Number,
    required: true
  },
  titleHeight: {
    type: Number,
    required: true
  },
  timeGranularity: {
    type: String as PropType<'year' | 'month' | 'day' | 'minute'>,
    default: ()=>{
      return 'month'
    }
  },
  endTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  startTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  getPositionOffset: {
    type: Function as PropType<(date: string) => number>,
    required: true
  },
  currentTime: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  }
});

const startDayOfRenderArea = computed(() => {
  return props.startTimeOfRenderArea ? startOfDay(new Date(props.startTimeOfRenderArea)) : new Date();
});

const endDayOfRenderArea = computed(() => {
  return props.endTimeOfRenderArea ? endOfDay(new Date(props.endTimeOfRenderArea)) : new Date();
});

const paddingWidth = computed(() => {
  // 根据时间粒度计算 paddingWidth
  const firstBlock = allBlocks.value[0];
  if (!firstBlock || isEqual(startDayOfRenderArea.value, firstBlockStart(firstBlock))) {
    return 0;
  } else {
    return props.getPositionOffset(firstBlock);
  }
});

const allBlocks = computed(() => {
  const { start, end, timeGranularity } = props;
  let blocks = [];
  let current = startOfYear(new Date(start));

  while (isBefore(current, end) || isEqual(current, end)) {
    switch (timeGranularity) {
      case 'year':
        blocks.push(current);
        current = startOfYear(addYears(current, 1));
        break;
      case 'month':
        blocks.push(current);
        current = startOfMonth(addMonths(current, 1));
        break;
      case 'day':
        blocks.push(current);
        current = startOfDay(addDays(current, 1));
        break;
      case 'minute':
        // 对于分钟刻度，我们需要按天计算，并在后续处理中生成每天的时间刻度
        let dayEnd = isSameDay(current, end) ? end : endOfDay(current);
        while (isBefore(current, dayEnd) || isEqual(current, dayEnd)) {
          blocks.push(current.toISOString()); // 存储为 ISO 字符串
          current = addMinutes(current, props.scale || MINUTE_OF_ONE_HOUR); // 假设默认刻度为1小时
        }
        current = addDays(dayEnd, 1);
        break;
      default:
        throw new Error('Invalid time granularity');
    }
  }

  // 对于年和月，我们可能需要转换为更易读的格式或对象
  return blocks.map(block => ({
    start: block,
    end: timeGranularity === 'minute' ? endOfDay(block) : add(block, 1, timeGranularity === 'year' ? 'year' : 'month')
  }));
});

const blockWidth = computed(() => {
  // 根据时间块数量和容器宽度动态计算每个时间块的宽度
  // 这里需要额外的逻辑来确定容器宽度，这里简化处理
  return (props.end.diff(props.start, timeGranularityToUnit(props.timeGranularity)) / allBlocks.value.length) * props.cellWidth;
});

const showTimeScale = computed(() => props.timeGranularity === 'day' || props.timeGranularity === 'minute');

const timeGranularityToUnit = (granularity: string): string => {
  switch (granularity) {
    case 'year':
      return 'year';
    case 'month':
      return 'month';
    case 'day':
      return 'day';
    case 'minute':
      return 'minute';
    default:
      return 'day'; // 默认情况下按天处理
  }
};

const firstBlockStart = (block: Date | { start: Date }) => (typeof block === 'object' ? block.start : block);

const formatBlock = (block: Date | { start: Date }) => {
  const date = firstBlockStart(block);
  switch (props.timeGranularity) {
    case 'year':
      return format(date, 'yyyy');
    case 'month':
      return format(date, 'yyyy-MM');
    case 'day':
      return format(date, 'yyyy-MM-dd');
    case 'minute':
      return format(date, 'yyyy-MM-dd'); // 对于分钟刻度，这里显示日期即可
    default:
      return '';
  }
};

const formatTime = (time: Date) => format(time, props.timeGranularity === 'minute' && props.scale < MINUTE_OF_ONE_HOUR ? 'HH:mm' : 'HH');

const getTimeScales = (block: { start: Date, end: Date }) => {
  if (props.timeGranularity === 'minute') {
    const start = block.start;
    const end = block.end;
    const scales: Date[] = [];
    let currentTime = startOfDay(start);
    while (isBefore(currentTime, end) || isEqual(currentTime, end)) {
      scales.push(currentTime);
      currentTime = addMinutes(currentTime, props.scale);
    }
    return scales;
  } else {
    return []; // 对于非分钟刻度，不返回时间刻度
  }
};

const cellWidthStyle = computed(() => ({
  width: `${props.cellWidth}px`
}));

const heightStyle = computed(() => ({
  height: props.titleHeight + 'px',
  lineHeight: props.titleHeight + 'px'
}));
</script>

<style scoped lang="scss">
/* 您的样式代码 */

.gantt-timeline-day {
  overflow: hidden;
  font-weight: bold;
  color: #666;
  border-right: 1px solid #aaa;
  border-bottom: 1px solid #ddd;
}

.gantt-timeline-scale {
  display: flex;
  border-right: 1px solid #aaa;

  & > div {
    height: 100%;
    font-size: 14px;
    color: #666;
    border-right: 1px solid #ddd;
  }
}
</style>
